package com.segersten.astro

import java.io.ObjectOutputStream
import java.io.ByteArrayOutputStream
import java.io.ObjectInputStream
import java.io.ByteArrayInputStream
import com.google.appengine.api.memcache.MemcacheService
import com.google.appengine.api.memcache.MemcacheServiceFactory
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.Calendar

class ViewController {
	
	private static final int NUMBER_OF_SENTENCES = 10
	private static final int DAY_OFFSET = -5
	
	def index = {
		render(text:"OK")
	}
	
	def startPage2 = {
		render(text:"requestURI ${request.requestURI}<br>")
		render(text:"requestURL ${request.requestURL}<br>")
		render(text:"host ${request.host}<br>")
		render(text:"request ${request}<br>")
		String []fs = "${request}".split(" ");
		render(text:"1request ${fs[1]}<br>")
		
		String []host = "${request.requestURI}".split("/");
		render(text:"host ${host[2]}<br>")
		
		def signs = Sign.findAll("select from Sign as s where s.language like :lan", [lan:"SWE%"])
		render(text:"Signs ${signs}<br>")
		
		String language = "SWE"
		String lan = "${language}%"
		List<Sign> signs2 = Sign.findAll("SELECT FROM Sign AS s WHERE s.language like :lang", [lang:lan])
		render(text:"Signs2 ${lan} ${signs2}<br>")
		
		
		Key key = new Key("hej",2,"hupp")
		render(text:"Key ${key}<br>")
		Entity ent = new Entity(new LinkedList<String>())
		render(text:"Entity ${ent}<br>")
		
		MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
		Date date = new Date();
		syncCache.put(date,ent);
		Entity ent2 = syncCache.get(date)
		render(text:"Entity2 ${ent2}<br>")
		
		/*ByteArrayOutputStream baus = new ByteArrayOutputStream()
		ObjectOutputStream oos = new ObjectOutputStream(baus)
		oos.writeObject(ent)
		render(text:"1<br>")
		render(text:"Obj '${ent.class.canonicalName}'<br>")
		byte[] data = baus.toByteArray()
		ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
		Object obj = ois.readObject()
		render(text:"Obj '${obj.class.canonicalName}'<br>")
		Entity ent2 = (Entity) obj
		render(text:"Entity2 ${ent2.created}<br>")*/
	}
	
	def fileNotFoundPage = {
		
	}
	
	def startPageRedirect = {
		redirect(uri:"/")
	}
	
	def startPage = {
		//LOG.info("Accessed startPage")
		// ugly hack to fix relative links
		String [] rs = "${request}".split(" ")
		String host
		if (rs.length > 2) {
			def url = rs[1] //.replace("http://mmxastrology.appspot.com", "")
			host = request.requestURL.toString().split("/")[2]
			if (true == url.contains("superstern"))
			{
				// redirect to supersterngezicht start page
				redirect(uri:"/ger/")
				return
			}
			else if (true == url.contains("swedish"))
			{
				// redirect to swedish start page
				redirect(uri:"/swe/")
				return
			}
			else if (true == url.contains("espanol"))
			{
				// redirect to swedish start page
				redirect(uri:"/esp/")
				return
			}
			else if (false == url.endsWith("/"))
			{
				// makes relative links work
				//render(text:"request ${url}<br>")
				redirect(uri:"/")
				return
			}
		}	
		response.setHeader("Cache-Control","max-age=600")
		[host:host]
	}
	
	def generateFirstPageMonth = {
		//LOG.info("Accessed generateFirstPageMonth ${params.language}")
		
		def language = params.language.toString().toUpperCase()
		
		def view = getLanguageFirstView(language)
		if (null == view) {
			response.status = 404
			return
		}
		
		// ugly hack to fix relative links
		String [] rs = "${request}".split(" ")
		String host
		if (rs.length > 2) {
			host = request.requestURL.toString().split("/")[2]
			def url = rs[1].toUpperCase() // .replace("http://mmxastrology.appspot.com", "").toUpperCase()
			String upperCaseURL = "/${language}/"
			if (false == url.endsWith(upperCaseURL)) // .equals(upperCaseURL))
			{
				// makes rel links work
				//render(text:"request2 >${url}<<br>")
				//render(text:"request2 >/PRED/${language}/MONTH/<<br>")
				redirect(uri:"/${language}/".toLowerCase())
				return
			}
		}
		
		def now = Calendar.getInstance()
		now.add(Calendar.DAY_OF_YEAR, DAY_OFFSET);
		def thisMonthIndex = now.get(Calendar.MONTH)+1
		def thisYear = now.get(Calendar.YEAR)
		now.add(Calendar.MONTH,1)
		def nextMonthIndex = now.get(Calendar.MONTH)+1
		def nextYear = now.get(Calendar.YEAR)
		def yearComposite = nextYear.equals(thisYear) ? thisYear : thisYear + " " + nextYear		
		def thisMonth = getMonthName(language, thisMonthIndex)
		def nextMonth = getMonthName(language, nextMonthIndex)
		
		def map = [thisIndex: thisMonthIndex, nextIndex: nextMonthIndex,
				   thisMonth:thisMonth , nextMonth:nextMonth, 
				   yearComposite : yearComposite, 
				   thisYear : thisYear,
				   nextYear : nextYear,
				   host : host]
		response.setHeader("Cache-Control","max-age=600")
		render(view:view, model:map)
	}
	
	def generateMonth = {
		//LOG.info("Accessed generateFirstPageMonth ${params.language}/${params.month}/${params.signId}")
		def language = params.language.toString().toUpperCase()
		def signId = params.sign
		def monthSource = params.month
		def month = getMonthIndex(params.month)
		def year = getYear(params.month)
		
		if (month==null) {
			response.status = 404
			return
		}
		
		def view = getLanguageView(language)
		if (null == view) {
			//render(text:"Language not found ${language} ${signId} ${month}")
			response.status = 404
			return
		}
		
		def sign = getSign(signId, language)
		if (!sign) {
			//render(text:"Sign not found ${language} ${signId} ${month}")
			response.status = 404
			return
		}
		
		def host = request.requestURL.toString().split("/")[2]
		
		String seed = signId+month+year
		Entity result = getPred(signId, month, language, seed)
		
		def monthName = getMonthName(language, month)
		//render(text:"<br>Result ${result.size()}<br>")
		def map = [sign:sign, prediction:result.getSenteneces(), type:"month", 
			period:month, year:year, month:monthName, monthSource:monthSource, host:host]
		response.setHeader("Cache-Control","max-age=600")
		render(view:view, model:map)
	}
	
	private String  getLanguageFirstView(String language) {
		def view = "monthDisplayFirstEng"
		if (language == "SWE") {
			view = "monthDisplayFirstSwe"
		} else if (language == "ENG") {
			view = "monthDisplayFirstEng"
		} else if (language == "GER") {
			view = "monthDisplayFirstGer"
		} else if (language == "ESP") {
			view = "monthDisplayFirstEsp"
		} else {
			return null
		}
		return view
	}
	
	private String getLanguageView(String language) {
		def view = "displayEng"
		if (language == "SWE") {
			view = "displaySwe"
		} else if (language == "ENG") {
			view = "displayEng"
		} else if (language == "GER") {
			view = "displayGer"
		} else if (language == "ESP") {
			view = "displayEsp"
		} else {
			return null
		}
		return view
	}
	
	private String getMonthName(String language, int monthIndex) {
		Calendar cal = Calendar.getInstance()
		//render(text:"${language} ${monthIndex}")
		def dates = [ 
					  "SWE" : [1:"Januari", 2:"Februari", 3:"Mars", 4:"April", 5:"Maj", 6:"Juni", 7:"Juli", 8:"Augusti", 9:"September", 10:"Oktober", 11:"November", 12:"December"],
					  "ENG" : [1:"January", 2:"February", 3:"Mars", 4:"April", 5:"May", 6:"June", 7:"July", 8:"August", 9:"September", 10:"October", 11:"November", 12:"December"],
					  "GER" : [1:"Januar", 2:"Februar", 3:"M&auml;rz", 4:"April", 5:"Mai", 6:"Juni", 7:"Ostermond", 8:"Augusti", 9:"September", 10:"Oktober", 11:"November", 12:"Dezember"],
					  "ESP" : [1:"Enero", 2:"Febrero", 3:"Marzo", 4:"Aprilo", 5:"Mayo", 6:"Junio", 7:"Julio", 8:"Augusto", 9:"Septiembre", 10:"Octubre", 11:"Noviembre", 12:"Diciembre"]
					]
		return dates[language][monthIndex]
	}
	
	private Entity getPred(String signId, int month, String language, String seed) {
		MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
		
		Key key = new Key(signId,month,language)
		Entity ent = (Entity)syncCache.get(key)
		
		if (ent!=null) {
			if (ent.getCreated().getTime()>new Date().getTime()-24*60*60*1000) {
				//System.out.println("READ FROM CAHCE!!!!");
				return ent
			}
		}
		
		//System.out.println("WRITE TO CAHCE!!!!");
		
		// TODO 1. put in mem cache per day if necessary, OR 2. cache result per day
		String langPredicate = "${language}%"
		List<Sentence> tempSentences = Sentence.findAll("SELECT FROM Sentence AS s WHERE s.language like :lang", [lang:langPredicate]);
		List<Sentence> sentences = new LinkedList<Sentence>(tempSentences)
		Random rand = new Random(seed.hashCode())
		String monthToken = month>9 ? Integer.toString(month) : String.format("0%d",month)
		String monthName = getMonthName(language, month)
		List<String> result = new LinkedList<String>()
		while(result.size()<NUMBER_OF_SENTENCES && sentences.size()>0) {
			int ndex = rand.nextInt(sentences.size());
			Sentence s = sentences.remove(ndex)
			if (s.getMonths().length()==0 || s.getMonths().contains(monthToken)) {
				result.add(pathMonth(s.sentence, monthName))
			}
		}
		ent = new Entity(result);
		syncCache.put(key,ent)
		return ent
	}
	
	private String pathMonth(String sentence, String month) {
		sentence = sentence.replace("M_manad", month).replace("m_manad", month.toLowerCase())
		return sentence
	}
	
	private Sign getSign(String signId, String language) {
		
		//List<Sign> signs = Sign.findAll("SELECT FROM Sign AS s WHERE s.language like :lang" AND s.signId = :sign", [lang:"${language}%", sign:Integer.parseInt(signId)])
		//render(text:"lan " + language + "<br>")
		//render(text:"signId " + signId + "<br>")
		String langPredicate = "${language}%"
		//render(text:"lanPred " + langPredicate + "<br>")
		List<Sign> signs = Sign.findAll("SELECT FROM Sign AS s WHERE s.language like :lang AND s.signId = :sign", [lang:langPredicate, sign:Integer.parseInt(signId)])
		
		//render(text:"signs " + signs + "<br>")
		return signs.isEmpty() ? null : signs.iterator().next()
		
	}
	
	private Integer getMonthIndex(String month) {
		//render(text:"month ${month}")
		if (month==null || month.equals("")) {
			throw new IllegalArgumentException("Unkown month");
		} else if ("this".equals(month)) {
			Calendar now = Calendar.getInstance()
			now.add(Calendar.DAY_OF_YEAR, DAY_OFFSET)
			return now.get(Calendar.MONTH)+1;
		} else if ("next".equals(month)) {
			Calendar now = Calendar.getInstance()
			now.add(Calendar.DAY_OF_YEAR, DAY_OFFSET)
			now.add(Calendar.MONTH,1)
			return now.get(Calendar.MONTH)+1;
		} else {
			try {
				int m = Integer.parseInt(month)
				return m>0&&m<13?m:null
			} catch (NumberFormatException e) {
				return null;
			}
		}
	}
	
	private int getYear(String month) {
		//render(text:"month ${month}")
		if (month==null || month.equals("")) {
			throw new IllegalArgumentException("Unkown month");
		} else if ("this".equals(month)) {
			Calendar now = Calendar.getInstance()
			now.add(Calendar.DAY_OF_YEAR, DAY_OFFSET)
			return now.get(Calendar.YEAR);
		} else if ("next".equals(month)) {
			Calendar now = Calendar.getInstance()
			now.add(Calendar.DAY_OF_YEAR, DAY_OFFSET)
			now.add(Calendar.MONTH,1)
			return now.get(Calendar.YEAR);
		} else {
			Calendar now = Calendar.getInstance()
			return now.get(Calendar.YEAR);
		}
	}
			
}
